package com.github.bridge.aspect;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.cglib.CglibUtil;
import cn.hutool.json.JSONUtil;
import com.github.bridge.controller.AuthController;
import com.github.bridge.domain.SysLog;
import com.github.bridge.request.BaseDTO;
import com.github.bridge.util.Const;
import com.github.bridge.util.R;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 系统日志切面处理类
 *
 * @author hui.zhang
 * @date 2021/1/28 11:04 上午
 */

@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class SysLogAspect {
    private final ThreadPoolExecutor customExecutor1;


    /**
     * 切点
     */
    @Pointcut("@annotation(com.github.bridge.annotation.SysLog)")
    public void logPointCut() {
    }

    /**
     * 环绕通知
     * @param joinPoint
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        return saveLog(joinPoint);
    }

    /**
     * 保存日志
     * @param joinPoint
     */
    private Object saveLog(ProceedingJoinPoint joinPoint) throws Throwable {
        SysLog sysLog = new SysLog();
        try {
            TimeInterval timer = DateUtil.timer();
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 请求方法名
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = signature.getName();
            // 请求的参数
            Object[] args = joinPoint.getArgs();
            String params = JSONUtil.toJsonStr(args);
            for (Object arg : args) {
                if (arg instanceof MultipartFile) {
                    continue;
                } else if (JSONUtil.isTypeJSON(arg.toString())) {
                    BaseDTO baseDTO = JSONUtil.toBean(arg.toString(), BaseDTO.class);
                    if (StrUtil.isNotBlank(baseDTO.getSystemId())) {
                        sysLog.setSystemId(baseDTO.getSystemId());
                        break;
                    }
                } else if (arg instanceof BaseDTO) {
                    BaseDTO baseDTO = CglibUtil.copy(arg, BaseDTO.class);
                    sysLog.setSystemId(baseDTO.getSystemId());
                    break;
                }
            }
            // 操作
            Method method = signature.getMethod();
            com.github.bridge.annotation.SysLog syslog = method.getAnnotation(com.github.bridge.annotation.SysLog.class);
            // 注解上的描述
            String action = syslog.value();

            sysLog.setSuccess(Const.YES);
            sysLog.setAction(action);
            sysLog.setRequestParam(params);
            sysLog.setUsable(Const.YES);
            sysLog.setCreateTime(LocalDateTime.now());

            Object proceed = joinPoint.proceed();

            // 花费毫秒数
            Long time = timer.interval();
            sysLog.setTime(time);
            if (AuthController.class.getName().equals(className)) {
                params = "[{\"*\":\"*\"}]";
            }
            String detail =  "访问:"+className + "." + methodName + "()"+" 传入:"+ params +" 执行:"+action+" 共用时:"+time +"毫秒";
            log.info(JSONUtil.toJsonStr(detail));
            R bean = JSONUtil.toBean(JSONUtil.toJsonStr(proceed), R.class);
            Object data = bean.getData();
            Map map = JSONUtil.toBean(JSONUtil.toJsonStr(data), Map.class);
            sysLog.setResponseParam(JSONUtil.toJsonStr(data));
            try {
                String provider = map.get("provider").toString();
                sysLog.setProvider(provider);
            } catch (Exception e) {
                log.error("没有解析到提供商");
            }
            return proceed;
        } catch (Exception t) {
            log.error(t.getMessage());
            sysLog.setSuccess(Const.NO);
            sysLog.setResponseParam(t.getMessage());
            throw t;
        } finally {
            customExecutor1.execute(sysLog::insert);
        }

    }

}
